package com.aloha.springframework.context.support;

import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.context.ApplicationEvent;
import com.aloha.springframework.context.ApplicationListener;
import com.aloha.springframework.context.event.ApplicationEventMulticaster;
import com.aloha.springframework.context.event.ContextClosedEvent;
import com.aloha.springframework.context.event.ContextRefreshedEvent;
import com.aloha.springframework.context.event.SimpleApplicationEventMulticaster;
import com.aloha.springframework.core.convert.ConversionService;
import com.aloha.springframework.core.io.DefaultResourceLoader;
import com.aloha.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.aloha.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.aloha.springframework.beans.factory.config.BeanPostProcessor;
import com.aloha.springframework.context.ConfigurableApplicationContext;

import java.util.Map;

/**
 * @author DaiZhiHeng
 * @description 定义了刷新容器的步骤，并将一些关键步骤扩展给子类实现
 * @date 2023/7/3 8:56
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
    public static final String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

    private ApplicationEventMulticaster applicationEventMulticaster;

    // 模板方法：创建BeanFactory并获得BeanDefinition
    protected abstract void refreshBeanFactory() throws BeansException;

    // 模板方法：获取BeanFactory
    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    @Override
    public void refresh() throws BeansException {

        // 这里跳过了Environment的准备

        // 1. 创建 BeanFactory，并加载 BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor，让实现 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 实例化之前，执行 BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5. 注册 BeanPostProcessor
        registerBeanPostProcessors(beanFactory);

        // 6. 初始化事件发布者
        initApplicationEventMulticaster();

        // 7. 注册事件监听器
        registerListeners();

        // 8. 注册类型转换器和提前实例化单例bean
        finishBeanFactoryInitialization(beanFactory);

        // 9. 发布容器刷新完成事件
        finishRefresh();
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public boolean containsBean(String name) {
        return getBeanFactory().containsBean(name);
    }

    @Override
    public void close() {
        // 发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));
        // 执行销毁单例bean的销毁方法
        getBeanFactory().destroySingletons();
    }

    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
    }

    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    @SuppressWarnings("unchecked")
    private void registerListeners() {
        getBeansOfType(ApplicationListener.class).values().forEach(listener -> applicationEventMulticaster.addApplicationListener(listener));
    }

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        //设置类型转换器
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
            Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
            if (conversionService instanceof ConversionService) {
                beanFactory.setConversionService((ConversionService) conversionService);
            }
        }

        //提前实例化单例bean
        beanFactory.preInstantiateSingletons();
    }

    private void finishRefresh() {
        // 发布容器已刷新的事件
        publishEvent(new ContextRefreshedEvent(this));
    }
}
